#include <stdio.h>
#include <errno.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <mosquitto.h>
#include <mqtt_protocol.h>

#include "config.h"
#include "mqtt_client_subscribe.h"

#define STATUS_CONNECTING 0
#define STATUS_CONNACK_RECVD 1
#define STATUS_WAITING 2
#define STATUS_DISCONNECTING 3
#define STATUS_DISCONNECTED 4
#define STATUS_NOHOPE 5

static volatile int status = STATUS_CONNECTING;

/* Callback called when the client receives a CONNACK message from the broker. */
void on_connect(struct mosquitto *mosq, void *obj, int result, int flags, const mosquitto_property *properties)
{
	/* Print out the connection result. mosquitto_connack_string() produces an
	 * appropriate string for MQTT v3.x clients, the equivalent for MQTT v5.0
	 * clients is mosquitto_reason_string().
	 */
	printf("on_connect: %s\n", mosquitto_connack_string(result));
	if(result != 0){
		/* If the connection fails for any reason, we don't want to keep on
		 * retrying in this example, so disconnect. Without this, the client
		 * will attempt to reconnect. */
		mosquitto_disconnect(mosq);
	}

	/* You may wish to set a flag here to indicate to your application that the
	 * client is now connected. */
}


/* Callback called when the client knows to the best of its abilities that a
 * PUBLISH has been successfully sent. For QoS 0 this means the message has
 * been completely written to the operating system. For QoS 1 this means we
 * have received a PUBACK from the broker. For QoS 2 this means we have
 * received a PUBCOMP from the broker. */
void on_publish(struct mosquitto *mosq, void *obj, int mid, int reason_code, const mosquitto_property *properties)
{
	char *reason_string = NULL;
	UNUSED(obj);
	UNUSED(properties);
	/* publish failed */
	if(reason_code > 127) {
		printf("Warning: Publish %d failed: %s.\n", mid, mosquitto_reason_string(reason_code));
		mosquitto_property_read_string(properties, MQTT_PROP_REASON_STRING, &reason_string, false);
		if(reason_string){
			fprintf(stderr, "%s\n", reason_string);
			free(reason_string);
		}
	} else
		printf("Message with mid %d has been published.\n", mid);
}

void on_disconnect(struct mosquitto *mosq, void *obj, int rc, const mosquitto_property *properties)
{
	UNUSED(mosq);
	UNUSED(obj);
	UNUSED(rc);
	UNUSED(properties);

	if(rc == 0) {
		status = STATUS_DISCONNECTED;
	}
}

MqttClientSubscribe::MqttClientSubscribe() : status(STATUS_CONNECTING)
,ready_for_repeat(false) {

}

MqttClientSubscribe::~MqttClientSubscribe() {

}


short MqttClientSubscribe::mqtt_client_subscribe(const char* topic) {

	int keepalive = 60;
	struct mosquitto *mosq;
	int rc;
	char* bind_address = "";
	mosquitto_property *mosq_config = NULL;

	/* Required before calling other mosquitto functions */
	mosquitto_lib_init();

	/* Create a new client instance.
	 * id = NULL -> ask the broker to generate a client id for us
	 * clean session = true -> the broker should remove old sessions when we connect
	 * obj = NULL -> we aren't passing any of our private data for callbacks
	 */
	mosq = mosquitto_new(NULL, true, NULL);
	if(mosq == NULL){
		fprintf(stderr, "Error: Out of memory.\n");
	}

	/* Configure callbacks. This should be done before connecting ideally. */
	mosquitto_connect_v5_callback_set(mosq, on_connect);
	mosquitto_disconnect_v5_callback_set(mosq, on_disconnect);
	mosquitto_publish_v5_callback_set(mosq, on_publish);


	/* Connect to test.mosquitto.org on port 1883, with a keepalive of 60 seconds.
	 * This call makes the socket connection only, it does not complete the MQTT
	 * CONNECT/CONNACK flow, you should use mosquitto_loop_start() or
	 * mosquitto_loop_forever() for processing net traffic. */
	rc = mosquitto_connect_bind_v5(mosq, "localhost", 1883, keepalive, bind_address, mosq_config);
	rc = mosquitto_connect(mosq, "test.mosquitto.org", 1883, 60);
	if(rc > 0) {
		if(rc == MOSQ_ERR_ERRNO){
			char* err = strerror(errno);
			fprintf(stderr, "Error: %s\n", err);
		} else {
			fprintf(stderr, "Unable to connect (%s).\n", mosquitto_strerror(rc));
		}
		mosquitto_lib_cleanup();
		return rc;
	}

	return MOSQ_ERR_SUCCESS;

	/* Run the network loop in a background thread, this call returns quickly. */
	rc = mosquitto_loop_start(mosq);
	if(rc != MOSQ_ERR_SUCCESS){
		mosquitto_destroy(mosq);
		fprintf(stderr, "Error: %s\n", mosquitto_strerror(rc));
		return 1;
	}
}




